var Faces = {
    None: 0,
    Front: 1,
    Right: 2,
    Behind: 3,
    Left: 4,
    Up: 5,
    Down: 6
};

var PerSize = [
    null,//0
    300,//1
    150,//2
    120,//3
    100,//4
    80,//5
    70,//6
    60,//7
    55,//8
    50,//9
    45,//10
    42,//11
    40,//12
    37,//13
    35,//14
    33//15
];

var Cube = function (N) {
    this.N = N;
    this.Persize = PerSize[N];
    this.Blocks = [];
    this.Center = 0;
};

Cube.prototype = {
    Init: function () {

        if (this.N > 15) return;
        if (this.N < 2) return;
        //一角的块数
        this.nCount = Math.floor(this.N / 2);
        //有无中棱块
        this.Center = this.N - 2 * this.nCount;

        for (var i = 0; i < this.N; i++) {
        }

        //添加中心块
        if (this.Center === 1 || this.N === 1) {
            var uC = new Block(0, 0, this.nCount, Color.None, Color.None, Color.Yellow);
            var dC = new Block(0, 0, -this.nCount, Color.None, Color.None, Color.White);
            var fC = new Block(0, this.nCount, 0, Color.None, Color.Blue, Color.None);
            var bC = new Block(0, -this.nCount, 0, Color.None, Color.Green, Color.None);
            var lC = new Block(-this.nCount, 0, 0, Color.Orange, Color.None, Color.Yellow);
            var rC = new Block(this.nCount, 0, 0, Color.Red, Color.None, Color.Yellow);
            this.Blocks.push(uC, dC, fC, bC, lC, rC);
        }

        ///添加角块
        if (this.N > 1) {
            var rfu = new Block(this.nCount, this.nCount, this.nCount, Color.Red, Color.Blue, Color.Yellow);
            var rfd = new Block(this.nCount, this.nCount, -this.nCount, Color.Red, Color.Blue, Color.White);
            var lfu = new Block(-this.nCount, this.nCount, this.nCount, Color.Orange, Color.Blue, Color.Yellow);
            var lfd = new Block(-this.nCount, this.nCount, -this.nCount, Color.Orange, Color.Blue, Color.White);
            var rbu = new Block(this.nCount, -this.nCount, this.nCount, Color.Red, Color.Green, Color.Yellow);
            var rbd = new Block(this.nCount, -this.nCount, -this.nCount, Color.Red, Color.Green, Color.White);
            var lbu = new Block(-this.nCount, -this.nCount, this.nCount, Color.Orange, Color.Green, Color.Yellow);
            var lbd = new Block(-this.nCount, -this.nCount, -this.nCount, Color.Orange, Color.Green, Color.White);

            this.Blocks.push(rfu, rfd, lfu, lfd, rbu, rbd, lbu, lbd);
        }

        //添加外中棱
        if (this.Center === 1 && this.N > 2) {
            var ru = new Block(this.nCount, 0, this.nCount, Color.Red, Color.None, Color.Yellow);
            var fu = new Block(0, this.nCount, this.nCount, Color.None, Color.Blue, Color.Yellow);
            var lu = new Block(-this.nCount, 0, this.nCount, Color.Orange, Color.None, Color.Yellow);
            var bu = new Block(0, -this.nCount, this.nCount, Color.None, Color.Green, Color.Yellow);
            var rf = new Block(this.nCount, this.nCount, 0, Color.Red, Color.Blue, Color.None);
            var lf = new Block(-this.nCount, this.nCount, 0, Color.Orange, Color.Blue, Color.None);
            var rb = new Block(this.nCount, -this.nCount, 0, Color.Red, Color.Green, Color.None);
            var lb = new Block(-this.nCount, -this.nCount, 0, Color.Orange, Color.Green, Color.None);
            var rd = new Block(this.nCount, 0, -this.nCount, Color.Red, Color.None, Color.White);
            var fd = new Block(0, this.nCount, -this.nCount, Color.None, Color.Blue, Color.White);
            var ld = new Block(-this.nCount, 0, -this.nCount, Color.Orange, Color.None, Color.White);
            var bd = new Block(0, -this.nCount, -this.nCount, Color.None, Color.Green, Color.White);

            this.Blocks.push(ru, fu, lu, bu, rf, lf, rb, lb, rd, fd, ld, bd);
        }

        //添加外边棱
        if (this.N > 3) {
            //RU
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(this.nCount, i, this.nCount, Color.Red, Color.None, Color.Yellow);
                    this.Blocks.push(b);
                }
            }
            //FU
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(i, this.nCount, this.nCount, Color.None, Color.Blue, Color.Yellow);
                    this.Blocks.push(b);
                }
            }
            //LU
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(-this.nCount, i, this.nCount, Color.Orange, Color.None, Color.Yellow);
                    this.Blocks.push(b);
                }
            }
            //BU
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(i, -this.nCount, this.nCount, Color.None, Color.Green, Color.Yellow);
                    this.Blocks.push(b);
                }
            }
            //RF
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(this.nCount, this.nCount, i, Color.Red, Color.Blue, Color.None);
                    this.Blocks.push(b);
                }
            }
            //LF
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(-this.nCount, this.nCount, i, Color.Orange, Color.Blue, Color.None);
                    this.Blocks.push(b);
                }
            }
            //RB
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(this.nCount, -this.nCount, i, Color.Red, Color.Green, Color.None);
                    this.Blocks.push(b);
                }
            }
            //LB
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(-this.nCount, -this.nCount, i, Color.Orange, Color.Green, Color.None);
                    this.Blocks.push(b);
                }
            }
            //RD
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(this.nCount, i, -this.nCount, Color.Red, Color.None, Color.White);
                    this.Blocks.push(b);
                }
            }
            //FD
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(i, this.nCount, -this.nCount, Color.None, Color.Blue, Color.White);
                    this.Blocks.push(b);
                }
            }
            //LD
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(-this.nCount, i, -this.nCount, Color.Orange, Color.None, Color.White);
                    this.Blocks.push(b);
                }
            }
            //BD
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                if (i !== 0) {
                    var b = new Block(i, -this.nCount, -this.nCount, Color.None, Color.Green, Color.White);
                    this.Blocks.push(b);
                }
            }
        }

        //添加内片（除中心块）
        if (this.N > 3) {
            //R
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                for (var j = -this.nCount + 1; j <= this.nCount - 1; j++) {
                    if (i !== 0 || j !== 0) {
                        var b = new Block(this.nCount, i, j, Color.Red, Color.None, Color.None);
                        if (this.Center === 0 && (i === 0 || j === 0)) continue;
                        this.Blocks.push(b);
                    }
                }
            }
            //L
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                for (var j = -this.nCount + 1; j <= this.nCount - 1; j++) {
                    if (i !== 0 || j !== 0) {
                        var b = new Block(-this.nCount, i, j, Color.Orange, Color.None, Color.None);
                        if (this.Center === 0 && (i === 0 || j === 0)) continue;
                        this.Blocks.push(b);
                    }
                }
            }
            //F
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                for (var j = -this.nCount + 1; j <= this.nCount - 1; j++) {
                    if (i !== 0 || j !== 0) {
                        var b = new Block(i, this.nCount, j, Color.None, Color.Blue, Color.None);
                        if (this.Center === 0 && (i === 0 || j === 0)) continue;
                        this.Blocks.push(b);
                    }
                }
            }
            //B
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                for (var j = -this.nCount + 1; j <= this.nCount - 1; j++) {
                    if (i !== 0 || j !== 0) {
                        var b = new Block(i, -this.nCount, j, Color.None, Color.Green, Color.None);
                        if (this.Center === 0 && (i === 0 || j === 0)) continue;
                        this.Blocks.push(b);
                    }
                }
            }
            //U
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                for (var j = -this.nCount + 1; j <= this.nCount - 1; j++) {
                    if (i !== 0 || j !== 0) {
                        var b = new Block(i, j, this.nCount, Color.None, Color.None, Color.Yellow);
                        if (this.Center === 0 && (i === 0 || j === 0)) continue;
                        this.Blocks.push(b);
                    }
                }
            }
            //D
            for (var i = -this.nCount + 1; i <= this.nCount - 1; i++) {
                for (var j = -this.nCount + 1; j <= this.nCount - 1; j++) {
                    if (i !== 0 || j !== 0) {
                        var b = new Block(i, j, -this.nCount, Color.None, Color.None, Color.White);
                        if (this.Center === 0 && (i === 0 || j === 0)) continue;
                        this.Blocks.push(b);
                    }
                }
            }
        }
    }
    ,
    Rotate: function (dms, step) {
        for (var i = 0; i < this.Blocks.length; i++) {
            this.Blocks[i].Rotate(dms, step);
        }
    }
    ,
    RotateLayer: function (face, layer, step) {
        var i;
        switch (face) {
            case Faces.Up || Faces.Down: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.Z === layer) {
                        this.Blocks[i].Rotate(Dimension.Z, step);
                    }
                }
                break;
            }
            case Faces.Right || Faces.Left: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.X === layer) {
                        this.Blocks[i].Rotate(Dimension.X, step);
                    }
                }
                break;
            }
            case Faces.Front || Faces.Behind: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.Y === layer) {
                        this.Blocks[i].Rotate(Dimension.Y, step);
                    }
                }
                break;
            }
        }
    }
    ,
    GetFace: function (faceIndex) {
        var floor = [];
        var i, j;
        var n = Math.floor(this.N / 2);
        switch (faceIndex) {
            case Faces.Up: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.Z === n) {
                        floor.push(this.Blocks[i]);
                    }
                }
                break;
            }
            case Faces.Down: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.Z === -n) {
                        floor.push(this.Blocks[i]);
                    }
                }
                break;
            }
            case Faces.Front: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.Y === n) {
                        floor.push(this.Blocks[i]);
                    }
                }
                break;
            }
            case Faces.Behind: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.Y === -n) {
                        floor.push(this.Blocks[i]);
                    }
                }
                break;
            }
            case Faces.Left: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.X === -n) {
                        floor.push(this.Blocks[i]);
                    }
                }
                break;
            }
            case Faces.Right: {
                for (i = 0; i < this.Blocks.length; i++) {
                    if (this.Blocks[i].Position.X === n) {
                        floor.push(this.Blocks[i]);
                    }
                }
                break;
            }
        }

        var face = [];
        //整理face
        switch (faceIndex) {
            case Faces.Up:
                for (i = -n; i <= n; i++) {
                    if (this.Center === 0 && i === 0)
                        continue;
                    for (j = -n; j <= n; j++) {
                        if (this.Center === 0 && j === 0) continue;
                        for (var k = floor.length - 1; k >= 0; k--) {
                            if (floor[k].Position.Y === i && floor[k].Position.X === j) {
                                face.push(floor[k].ColorVector.Z);
                                floor.splice(k, 1);
                                break;
                            }
                        }
                    }
                }
                break;
            case Faces.Down:
                for (i = n; i >= -n; i--) {
                    if (this.Center === 0 && i === 0)
                        continue;
                    for (j = -n; j <= n; j++) {
                        if (this.Center === 0 && j === 0) continue;
                        for (var k = floor.length - 1; k >= 0; k--) {
                            if (floor[k].Position.Y === i && floor[k].Position.X === j) {
                                face.push(floor[k].ColorVector.Z);
                                floor.splice(k, 1);
                                break;
                            }
                        }
                    }
                }
                break;
            case Faces.Front:
                for (i = n; i >= -n; i--) {
                    if (this.Center === 0 && i === 0)
                        continue;
                    for (j = -n; j <= n; j++) {
                        if (this.Center === 0 && j === 0) continue;
                        for (var k = floor.length - 1; k >= 0; k--) {
                            if (floor[k].Position.Z === i && floor[k].Position.X === j) {
                                face.push(floor[k].ColorVector.Y);
                                floor.splice(k, 1);
                                break;
                            }
                        }
                    }
                }
                break;
            case Faces.Behind:
                for (i = n; i >= -n; i--) {
                    if (this.Center === 0 && i === 0)
                        continue;
                    for (j = n; j >= -n; j--) {
                        if (this.Center === 0 && j === 0) continue;
                        for (var k = floor.length - 1; k >= 0; k--) {
                            if (floor[k].Position.Z === i && floor[k].Position.X === j) {
                                face.push(floor[k].ColorVector.Y);
                                floor.splice(k, 1);
                                break;
                            }
                        }
                    }
                }
                break;
            case Faces.Left:
                for (i = n; i >= -n; i--) {
                    if (this.Center === 0 && i === 0)
                        continue;
                    for (j = -n; j <= n; j++) {
                        if (this.Center === 0 && j === 0) continue;
                        for (var k = floor.length - 1; k >= 0; k--) {
                            if (floor[k].Position.Z === i && floor[k].Position.Y === j) {
                                face.push(floor[k].ColorVector.X);
                                floor.splice(k, 1);
                                break;
                            }
                        }
                    }
                }
                break;
            case Faces.Right:
                for (i = n; i >= -n; i--) {
                    if (this.Center === 0 && i === 0)
                        continue;
                    for (j = n; j >= -n; j--) {
                        if (this.Center === 0 && j === 0) continue;
                        for (var k = floor.length - 1; k >= 0; k--) {
                            if (floor[k].Position.Z === i && floor[k].Position.Y === j) {
                                face.push(floor[k].ColorVector.X);
                                floor.splice(k, 1);
                                break;
                            }
                        }
                    }
                }
                break;
        }

        return face;
    }
    ,
    RotateRandom: function () {
        if (this.N <= 3) {
            var index = getRandom(1, 19);
            switch (index) {
                case 18:
                    this.RotateU();
                    break;
                case 1:
                    this.RotateU_();
                    break;
                case 2:
                    this.RotateD();
                    break;
                case 3:
                    this.RotateD_();
                    break;
                case 4:
                    this.RotateF();
                    break;
                case 5:
                    this.RotateF_();
                    break;
                case 6:
                    this.RotateB();
                    break;
                case 7:
                    this.RotateB_();
                    break;
                case 8:
                    this.RotateL();
                    break;
                case 9:
                    this.RotateL_();
                    break;
                case 10:
                    this.RotateR();
                    break;
                case 11:
                    this.RotateR_();
                    break;
                case 12:
                    this.RotateS();
                    break;
                case 13:
                    this.RotateS_();
                    break;
                case 14:
                    this.RotateE();
                    break;
                case 15:
                    this.RotateE_();
                    break;
                case 16:
                    this.RotateM();
                    break;
                case 17:
                    this.RotateM_();
                    break;
            }
        } else {
            var faces = [Faces.Up, Faces.Down, Faces.Front, Faces.Green, Faces.Left, Faces.Right];
            var face = faces[getRandom(0, 6)];
            var layers = [];
            var n = Math.floor(this.N / 2);
            for (var i = 0; i < this.N; i++) {
                if (i - n === n && this.Center === 0) continue;
                layers[i] = i - n;
            }
            var layer = layers[getRandom(0, layers.length)];
            var step = getRandom(1, 4);
            this.RotateLayer(face, layer, step);
        }
    }
    ,
    Break: function () {
        var count = this.N * this.N * this.N * 2;
        for (var i = 0; i < count; i++) {
            this.RotateRandom();
        }
    }
    ,
    RotateX: function () {
        this.Rotate(Dimension.X, 1);
    },
    RotateY: function () {
        this.Rotate(Dimension.Y, 1);
    },
    RotateZ: function () {
        this.Rotate(Dimension.Z, 1);
    },
    RotateX_: function () {
        this.Rotate(Dimension.X, 3);
    },
    RotateY_: function () {
        this.Rotate(Dimension.Y, 3);
    },
    RotateZ_: function () {
        this.Rotate(Dimension.Z, 3);
    },
    RotateU_: function () {
        this.RotateLayer(Faces.Up, this.nCount, 3);
    },
    RotateD: function () {
        this.RotateLayer(Faces.Down, -this.nCount, 3);
    },
    RotateF_: function () {
        this.RotateLayer(Faces.Front, this.nCount, 3);
    },
    RotateB: function () {
        this.RotateLayer(Faces.Front, -this.nCount, 3);
    },
    RotateL: function () {
        this.RotateLayer(Faces.Right, -this.nCount, 3);
    },
    RotateR_: function () {
        this.RotateLayer(Faces.Right, this.nCount, 3);
    },
    RotateU: function () {
        this.RotateLayer(Faces.Up, this.nCount, 1);
    },
    RotateD_: function () {
        this.RotateLayer(Faces.Up, -this.nCount, 1);
    },
    RotateF: function () {
        this.RotateLayer(Faces.Front, this.nCount, 1);
    },
    RotateB_: function () {
        this.RotateLayer(Faces.Front, -this.nCount, 1);
    },
    RotateL_: function () {
        this.RotateLayer(Faces.Right, -this.nCount, 1);
    },
    RotateR: function () {
        this.RotateLayer(Faces.Right, this.nCount, 1);
    },
    RotateE: function () {
        this.RotateLayer(Faces.Up, 0, 1);
    },
    RotateM: function () {
        this.RotateLayer(Faces.Right, 0, 1);
    },
    RotateS: function () {
        this.RotateLayer(Faces.Front, 0, 1);
    },
    RotateE_: function () {
        this.RotateLayer(Faces.Up, 0, 3);
    },
    RotateM_: function () {
        this.RotateLayer(Faces.Right, 0, 3);
    },
    RotateS_: function () {
        this.RotateLayer(Faces.Front, 0, 3);
    },
    RotateControl: function (face, layer, step) {
        if (layer === 0 && this.Center === 0) return;
        this.RotateLayer(face, layer, step);
    },
    RotateControlT: function (face, index, step) {
        var layer = index - this.nCount;
        if (this.Center === 0 && layer >= 0) layer += 1;
        this.RotateControl(face, layer, step);
    },
    RotateCube: function (dms) {
        switch (dms) {
            case Dimension.X:
                this.RotateX();
                break;
            case Dimension.X_:
                this.RotateX_();
                break;
            case Dimension.Y:
                this.RotateY();
                break;
            case Dimension.Y_:
                this.RotateY_();
                break;
            case Dimension.Z:
                this.RotateZ();
                break;
            case Dimension.Z_:
                this.RotateZ_();
                break;
        }
    }
};

//产生begin到end（不包含end）之间的随机数
function getRandom(begin, end) {
    var rd = Math.random() * (end - begin);
    rd = Math.floor(rd);
    rd += begin;
    return rd;
}